import mongoose, { Document, Schema, Model } from 'mongoose';

/**
 * 角色权限关联接口定义
 * 定义角色权限关联的基本属性
 */
export interface IRolePermission {
  /** 角色ID */
  roleId: mongoose.Types.ObjectId;
  /** 权限ID */
  permissionId: mongoose.Types.ObjectId;
  /** 所属系统ID（可选，用于多系统权限管理） */
  systemId?: mongoose.Types.ObjectId;
  /** 分配人ID */
  assignedBy: mongoose.Types.ObjectId;
  /** 分配时间 */
  assignedAt: Date;
  /** 过期时间（可选） */
  expiresAt?: Date;
  /** 状态：1-正常，0-禁用 */
  status: number;
  /** 创建时间 */
  createdAt: Date;
  /** 更新时间 */
  updatedAt: Date;
}

/**
 * 角色权限关联文档接口
 * 继承IRolePermission接口和mongoose的Document接口
 */
export interface IRolePermissionDocument extends IRolePermission, Document {
  /**
   * 转换为JSON格式，用于API响应
   * @returns 格式化的角色权限关联对象
   */
  toJSON(): any;

  /**
   * 检查角色权限关联是否已过期
   * @returns 是否已过期
   */
  isExpired(): boolean;

  /**
   * 检查角色权限关联是否可以被删除
   * @returns 是否可以删除
   */
  canBeDeleted(): Promise<boolean>;

  /**
   * 获取角色权限关联的详细信息（包含角色和权限信息）
   * @returns 详细信息对象
   */
  getDetailInfo(): Promise<any>;
}

/**
 * 角色权限关联模型接口
 * 定义角色权限关联模型的静态方法
 */
export interface IRolePermissionModel extends Model<IRolePermissionDocument> {
  /**
   * 根据角色ID查找权限关联
   * @param roleId 角色ID
   * @returns 角色权限关联文档数组
   */
  findByRoleId(roleId: mongoose.Types.ObjectId): Promise<IRolePermissionDocument[]>;

  /**
   * 根据权限ID查找角色关联
   * @param permissionId 权限ID
   * @returns 角色权限关联文档数组
   */
  findByPermissionId(permissionId: mongoose.Types.ObjectId): Promise<IRolePermissionDocument[]>;

  /**
   * 根据系统ID查找角色权限关联
   * @param systemId 系统ID
   * @returns 角色权限关联文档数组
   */
  findBySystemId(systemId: mongoose.Types.ObjectId): Promise<IRolePermissionDocument[]>;

  /**
   * 检查角色是否拥有指定权限
   * @param roleId 角色ID
   * @param permissionId 权限ID
   * @param systemId 系统ID（可选）
   * @returns 是否拥有权限
   */
  hasPermission(
    roleId: mongoose.Types.ObjectId,
    permissionId: mongoose.Types.ObjectId,
    systemId?: mongoose.Types.ObjectId
  ): Promise<boolean>;

  /**
   * 批量分配权限给角色
   * @param roleId 角色ID
   * @param permissionIds 权限ID数组
   * @param assignedBy 分配人ID
   * @param systemId 系统ID（可选）
   * @param expiresAt 过期时间（可选）
   * @returns 创建的角色权限关联文档数组
   */
  batchAssign(
    roleId: mongoose.Types.ObjectId,
    permissionIds: mongoose.Types.ObjectId[],
    assignedBy: mongoose.Types.ObjectId,
    systemId?: mongoose.Types.ObjectId,
    expiresAt?: Date
  ): Promise<IRolePermissionDocument[]>;

  /**
   * 批量撤销角色的权限
   * @param roleId 角色ID
   * @param permissionIds 权限ID数组（可选，不传则撤销所有权限）
   * @param systemId 系统ID（可选）
   * @returns 撤销的数量
   */
  batchRevoke(
    roleId: mongoose.Types.ObjectId,
    permissionIds?: mongoose.Types.ObjectId[],
    systemId?: mongoose.Types.ObjectId
  ): Promise<number>;

  /**
   * 获取角色在指定系统中的权限列表
   * @param roleId 角色ID
   * @param systemId 系统ID（可选）
   * @returns 权限ID数组
   */
  getRolePermissionsInSystem(
    roleId: mongoose.Types.ObjectId,
    systemId?: mongoose.Types.ObjectId
  ): Promise<mongoose.Types.ObjectId[]>;

  /**
   * 获取即将过期的角色权限关联
   * @param days 天数，默认7天
   * @returns 即将过期的角色权限关联文档数组
   */
  getExpiringPermissions(days?: number): Promise<IRolePermissionDocument[]>;

  /**
   * 清理已过期的角色权限关联
   * @returns 清理的数量
   */
  cleanupExpiredPermissions(): Promise<number>;

  /**
   * 同步角色权限（用于权限变更时的同步）
   * @param roleId 角色ID
   * @param permissionIds 新的权限ID数组
   * @param assignedBy 分配人ID
   * @param systemId 系统ID（可选）
   * @returns 同步结果
   */
  syncRolePermissions(
    roleId: mongoose.Types.ObjectId,
    permissionIds: mongoose.Types.ObjectId[],
    assignedBy: mongoose.Types.ObjectId,
    systemId?: mongoose.Types.ObjectId
  ): Promise<{
    added: IRolePermissionDocument[];
    removed: number;
  }>;

  /**
   * 获取权限被分配给的角色数量
   * @param permissionId 权限ID
   * @returns 角色数量
   */
  getPermissionRoleCount(permissionId: mongoose.Types.ObjectId): Promise<number>;

  /**
   * 获取角色拥有的权限数量
   * @param roleId 角色ID
   * @returns 权限数量
   */
  getRolePermissionCount(roleId: mongoose.Types.ObjectId): Promise<number>;
}

/**
 * 角色权限关联Schema定义
 */
const RolePermissionSchema = new Schema<IRolePermissionDocument>({
  // 角色ID
  roleId: {
    type: Schema.Types.ObjectId,
    ref: 'Role',
    required: [true, '角色ID不能为空'],
    index: true,
    validate: {
      validator: function(value: any) {
        return mongoose.Types.ObjectId.isValid(value);
      },
      message: '无效的角色ID'
    }
  },

  // 权限ID
  permissionId: {
    type: Schema.Types.ObjectId,
    ref: 'Permission',
    required: [true, '权限ID不能为空'],
    index: true
  },

  // 系统ID（可选，用于多系统权限管理）
  systemId: {
    type: Schema.Types.ObjectId,
    ref: 'System',
    index: true
  },

  // 分配人ID
  assignedBy: {
    type: Schema.Types.ObjectId,
    ref: 'User',
    required: [true, '分配人ID不能为空'],
    index: true
  },

  // 分配时间
  assignedAt: {
    type: Date,
    required: true,
    default: Date.now,
    index: true
  },

  // 过期时间（可选）
  expiresAt: {
    type: Date,
    index: true
  },

  // 状态：1-正常，0-禁用
  status: {
    type: Number,
    required: true,
    enum: [0, 1],
    default: 1,
    index: true
  }
}, {
  // 自动添加创建时间和更新时间
  timestamps: true,
  // 集合名称
  collection: 'role_permissions',
  // 禁用版本键
  versionKey: false
});

// 复合索引
RolePermissionSchema.index({ roleId: 1, permissionId: 1 }, { unique: true });
RolePermissionSchema.index({ roleId: 1, systemId: 1 });
RolePermissionSchema.index({ permissionId: 1, systemId: 1 });
RolePermissionSchema.index({ roleId: 1, status: 1 });
RolePermissionSchema.index({ permissionId: 1, status: 1 });
RolePermissionSchema.index({ systemId: 1, status: 1 });
RolePermissionSchema.index({ assignedBy: 1, assignedAt: -1 });
RolePermissionSchema.index({ expiresAt: 1 }, { sparse: true });
RolePermissionSchema.index({ status: 1, createdAt: -1 });

// 保存前中间件：设置默认值和验证
RolePermissionSchema.pre('save', function(next) {
  // 如果是新文档，设置默认值
  if (this.isNew) {
    // 设置分配时间
    if (!this.assignedAt) {
      this.assignedAt = new Date();
    }
    
    // 只有当status未定义时才设置默认值
    if (this.status === undefined) {
      this.status = 1;
    }
  }
  
  next();
});

// 更新前中间件：处理更新操作
RolePermissionSchema.pre(['updateOne', 'findOneAndUpdate'], function(next) {
  const update = this.getUpdate() as any;
  
  // 自动更新updatedAt字段
  update.updatedAt = new Date();
  
  next();
});

// 实例方法：转换为JSON格式
RolePermissionSchema.methods.toJSON = function() {
  const obj = this.toObject();
  
  // 移除版本字段
  delete obj.__v;
  
  // 格式化时间字段
  if (obj.createdAt) {
    obj.createdAt = obj.createdAt.toISOString();
  }
  if (obj.updatedAt) {
    obj.updatedAt = obj.updatedAt.toISOString();
  }
  if (obj.assignedAt) {
    obj.assignedAt = obj.assignedAt.toISOString();
  }
  if (obj.expiresAt) {
    obj.expiresAt = obj.expiresAt.toISOString();
  }
  
  return obj;
};

// 实例方法：检查是否已过期
RolePermissionSchema.methods.isExpired = function(): boolean {
  if (!this.expiresAt) {
    return false;
  }
  return new Date() > this.expiresAt;
};

// 实例方法：检查是否可以被删除
RolePermissionSchema.methods.canBeDeleted = async function(): Promise<boolean> {
  // 角色权限关联通常都可以删除，除非有特殊业务逻辑
  return true;
};

// 实例方法：获取详细信息
RolePermissionSchema.methods.getDetailInfo = async function(): Promise<any> {
  const populated = await this.populate([
    { path: 'roleId', select: 'name code description level' },
    { path: 'permissionId', select: 'name code type description' },
    { path: 'assignedBy', select: 'username email' }
  ]);
  
  return populated.toJSON();
};

// 静态方法：根据角色ID查找权限关联
RolePermissionSchema.statics.findByRoleId = function(
  roleId: mongoose.Types.ObjectId
): Promise<IRolePermissionDocument[]> {
  return this.find({ 
    roleId,
    status: 1
  }).sort({ createdAt: -1 });
};

// 静态方法：根据权限ID查找角色关联
RolePermissionSchema.statics.findByPermissionId = function(
  permissionId: mongoose.Types.ObjectId
): Promise<IRolePermissionDocument[]> {
  return this.find({ 
    permissionId,
    status: 1
  }).sort({ createdAt: -1 });
};

// 静态方法：根据系统ID查找角色权限关联
RolePermissionSchema.statics.findBySystemId = function(
  systemId: mongoose.Types.ObjectId
): Promise<IRolePermissionDocument[]> {
  return this.find({ 
    systemId,
    status: 1
  }).sort({ createdAt: -1 });
};

// 静态方法：检查角色是否拥有指定权限
RolePermissionSchema.statics.hasPermission = async function(
  roleId: mongoose.Types.ObjectId,
  permissionId: mongoose.Types.ObjectId,
  systemId?: mongoose.Types.ObjectId
): Promise<boolean> {
  const query: any = {
    roleId,
    permissionId,
    status: 1
  };
  
  if (systemId) {
    query.systemId = systemId;
  }
  
  // 检查是否过期
  query.$or = [
    { expiresAt: { $exists: false } },
    { expiresAt: null },
    { expiresAt: { $gt: new Date() } }
  ];
  
  const rolePermission = await this.findOne(query);
  return !!rolePermission;
};

// 静态方法：批量分配权限给角色
RolePermissionSchema.statics.batchAssign = async function(
  roleId: mongoose.Types.ObjectId,
  permissionIds: mongoose.Types.ObjectId[],
  assignedBy: mongoose.Types.ObjectId,
  systemId?: mongoose.Types.ObjectId,
  expiresAt?: Date
): Promise<IRolePermissionDocument[]> {
  const rolePermissions = permissionIds.map(permissionId => ({
    roleId,
    permissionId,
    systemId,
    assignedBy,
    assignedAt: new Date(),
    expiresAt,
    status: 1
  }));
  
  // 使用upsert避免重复插入
  const result: IRolePermissionDocument[] = [];
  
  for (const rp of rolePermissions) {
    const query: any = {
      roleId: rp.roleId,
      permissionId: rp.permissionId
    };
    
    if (systemId) {
      query.systemId = systemId;
    }
    
    const updated = await this.findOneAndUpdate(
      query,
      {
        $set: {
          assignedBy: rp.assignedBy,
          assignedAt: rp.assignedAt,
          expiresAt: rp.expiresAt,
          status: 1,
          updatedAt: new Date()
        }
      },
      {
        upsert: true,
        new: true
      }
    );
    
    result.push(updated);
  }
  
  return result;
};

// 静态方法：批量撤销角色的权限
RolePermissionSchema.statics.batchRevoke = async function(
  roleId: mongoose.Types.ObjectId,
  permissionIds?: mongoose.Types.ObjectId[],
  systemId?: mongoose.Types.ObjectId
): Promise<number> {
  const query: any = { roleId };
  
  if (permissionIds && permissionIds.length > 0) {
    query.permissionId = { $in: permissionIds };
  }
  
  if (systemId) {
    query.systemId = systemId;
  }
  
  const result = await this.updateMany(
    query,
    {
      $set: {
        status: 0,
        updatedAt: new Date()
      }
    }
  );
  
  return result.modifiedCount;
};

// 静态方法：获取角色在指定系统中的权限列表
RolePermissionSchema.statics.getRolePermissionsInSystem = async function(
  roleId: mongoose.Types.ObjectId,
  systemId?: mongoose.Types.ObjectId
): Promise<mongoose.Types.ObjectId[]> {
  const query: any = {
    roleId,
    status: 1
  };
  
  if (systemId) {
    query.systemId = systemId;
  }
  
  // 排除过期的权限
  query.$or = [
    { expiresAt: { $exists: false } },
    { expiresAt: null },
    { expiresAt: { $gt: new Date() } }
  ];
  
  const rolePermissions = await this.find(query, 'permissionId');
  return rolePermissions.map((rp: IRolePermissionDocument) => rp.permissionId);
};

// 静态方法：获取即将过期的角色权限关联
RolePermissionSchema.statics.getExpiringPermissions = function(
  days: number = 7
): Promise<IRolePermissionDocument[]> {
  const expiryDate = new Date();
  expiryDate.setDate(expiryDate.getDate() + days);
  
  return this.find({
    expiresAt: {
      $exists: true,
      $ne: null,
      $lte: expiryDate,
      $gt: new Date()
    },
    status: 1
  }).sort({ expiresAt: 1 });
};

// 静态方法：清理已过期的角色权限关联
RolePermissionSchema.statics.cleanupExpiredPermissions = async function(): Promise<number> {
  const result = await this.updateMany(
    {
      expiresAt: {
        $exists: true,
        $ne: null,
        $lt: new Date()
      },
      status: 1
    },
    {
      $set: {
        status: 0,
        updatedAt: new Date()
      }
    }
  );
  
  return result.modifiedCount;
};

// 静态方法：同步角色权限
RolePermissionSchema.statics.syncRolePermissions = async function(
  roleId: mongoose.Types.ObjectId,
  permissionIds: mongoose.Types.ObjectId[],
  assignedBy: mongoose.Types.ObjectId,
  systemId?: mongoose.Types.ObjectId
): Promise<{
  added: IRolePermissionDocument[];
  removed: number;
}> {
  // 获取当前权限
  const currentPermissions = await (this as IRolePermissionModel).getRolePermissionsInSystem(roleId, systemId);
  const currentPermissionIds = currentPermissions.map((id: mongoose.Types.ObjectId) => id.toString());
  const newPermissionIds = permissionIds.map((id: mongoose.Types.ObjectId) => id.toString());
  
  // 计算需要添加和删除的权限
  const toAdd = permissionIds.filter((id: mongoose.Types.ObjectId) => !currentPermissionIds.includes(id.toString()));
  const toRemove = currentPermissions.filter((id: mongoose.Types.ObjectId) => !newPermissionIds.includes(id.toString()));
  
  // 添加新权限
  const added = toAdd.length > 0 
    ? await (this as IRolePermissionModel).batchAssign(roleId, toAdd, assignedBy, systemId)
    : [];
  
  // 删除旧权限
  const removed = toRemove.length > 0 
    ? await (this as IRolePermissionModel).batchRevoke(roleId, toRemove, systemId)
    : 0;
  
  return { added, removed };
};

// 静态方法：获取权限被分配给的角色数量
RolePermissionSchema.statics.getPermissionRoleCount = async function(
  permissionId: mongoose.Types.ObjectId
): Promise<number> {
  return await this.countDocuments({
    permissionId,
    status: 1,
    $or: [
      { expiresAt: { $exists: false } },
      { expiresAt: null },
      { expiresAt: { $gt: new Date() } }
    ]
  });
};

// 静态方法：获取角色拥有的权限数量
RolePermissionSchema.statics.getRolePermissionCount = async function(
  roleId: mongoose.Types.ObjectId
): Promise<number> {
  return await this.countDocuments({
    roleId,
    status: 1,
    $or: [
      { expiresAt: { $exists: false } },
      { expiresAt: null },
      { expiresAt: { $gt: new Date() } }
    ]
  });
};

// 导出角色权限关联模型
export const RolePermission = mongoose.model<IRolePermissionDocument, IRolePermissionModel>(
  'RolePermission',
  RolePermissionSchema
);

export default RolePermission;